package com.example.activitiydemo.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.example.activitiydemo.dao.ActGeBytearrayMapper;
import com.example.activitiydemo.entity.ActGeBytearray;
import com.example.activitiydemo.service.IDemoService;
import lombok.Data;
import org.activiti.bpmn.BpmnAutoLayout;
import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.*;
import org.activiti.bpmn.model.Process;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricActivityInstanceQuery;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.impl.persistence.deploy.DeploymentManager;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class DemoServiceImpl implements IDemoService {

	@Override
	public Object startTask(String taskName) {
		//        1、创建ProcessEngine
		ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//        2、获取RunTimeService
		RuntimeService runtimeService = processEngine.getRuntimeService();
//        3、根据流程定义Id启动流程
		ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(taskName);
//        输出内容
		System.out.println("流程定义id：" + processInstance.getProcessDefinitionId());
		System.out.println("流程实例id：" + processInstance.getId());
		System.out.println("当前活动Id：" + processInstance.getActivityId());
		final ProcessInstanceVo processInstanceVo = new ProcessInstanceVo();
		processInstanceVo.setProcessDefinitionId(processInstance.getProcessDefinitionId());
		processInstanceVo.setId(processInstance.getId());
		processInstanceVo.setActivityId(processInstance.getActivityId());
		return processInstanceVo;
	}

	@Override
	public Object getTask(String assignee) {
		//        任务负责人
//		String assignee = "张三";
//		String assignee = assignee;
		ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//        创建TaskService
		TaskService taskService = processEngine.getTaskService();
//        根据流程key 和 任务负责人 查询任务
		List<Task> list = taskService.createTaskQuery()
//				.processDefinitionKey("test") //流程Key
				.taskAssignee(assignee)//只查询该任务负责人的任务
				.list();
		for (Task task : list) {
			System.out.println("----------------------------");
			System.out.println("流程实例id：" + task.getProcessInstanceId());
			System.out.println("任务id：" + task.getId());
			System.out.println("任务负责人：" + task.getAssignee());
			System.out.println("任务名称：" + task.getName());
		}
		final List<TaskVo> data = list.stream().map(item -> {
			TaskVo vo = new TaskVo();
			vo.setProcessInstanceId(item.getProcessInstanceId());
			vo.setId(item.getId());
			vo.setAssignee(item.getAssignee());
			vo.setName(item.getName());
			return vo;
		}).collect(Collectors.toList());
		return JSONObject.toJSONString(data, true);
	}

	@Override
	public Object getTaskHistory(String proInsId) {
		//      获取引擎
		ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//        获取HistoryService
		HistoryService historyService = processEngine.getHistoryService();
//        获取 actinst表的查询对象
		HistoricActivityInstanceQuery instanceQuery = historyService.createHistoricActivityInstanceQuery();
//        查询 actinst表，条件：根据 InstanceId 查询，查询一个流程的所有历史信息
		instanceQuery.processInstanceId(proInsId);
//        查询 actinst表，条件：根据 DefinitionId 查询，查询一种流程的所有历史信息
//        instanceQuery.processDefinitionId("myLeave:1:22504");
//        增加排序操作,orderByHistoricActivityInstanceStartTime 根据开始时间排序 asc 升序
		instanceQuery.orderByHistoricActivityInstanceStartTime().asc();
//        查询所有内容
		List<HistoricActivityInstance> activityInstanceList = instanceQuery.list();
//        输出
		for (HistoricActivityInstance hi : activityInstanceList) {
			if (hi.getActivityName() != null) {
				System.out.println(hi.getActivityId());
				System.out.println(hi.getActivityName());
				System.out.println(hi.getProcessDefinitionId());
				System.out.println(hi.getProcessInstanceId());
				System.out.println("<==========================>");
			}
		}
		final List<HistoricActivityInstanceVo> data = activityInstanceList.stream().filter(item -> item.getActivityName() != null)
				.map(item -> {
					HistoricActivityInstanceVo vo = new HistoricActivityInstanceVo();
					vo.setActivityId(item.getActivityId());
					vo.setActivityName(item.getActivityName());
					vo.setProcessDefinitionId(item.getProcessDefinitionId());
					vo.setProcessInstanceId(item.getProcessInstanceId());
					return vo;
				}).collect(Collectors.toList());
		return JSONObject.toJSONString(data, true);
	}

	@Override
	public Object completeTask(String taskId, String assignee) {
		//        流程定义的Key
//		String key = "test";
//        任务负责人
//		String assingee = "张三";
//		String assingee = "李四3";
//		String assingee = "王五";

//        String assingee = "张财务";
		//        获取流程引擎
		ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//        获取taskservice
		TaskService taskService = processEngine.getTaskService();
//        查询任务
		Task task = taskService.createTaskQuery()
				.taskId(taskId)
				.taskAssignee(assignee)
				.singleResult();
		if(task != null){
			//     根据任务id来   完成任务
			taskService.complete(task.getId());
		}
		return "成功";
	}

	@Override
	public Object returnAppointNode(String taskId, String assignee) {
		//        1、创建ProcessEngine
		ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
		final TaskService taskService = processEngine.getTaskService();
		final HistoryService historyService = processEngine.getHistoryService();
		final RepositoryService repositoryService = processEngine.getRepositoryService();
		final RuntimeService runtimeService = processEngine.getRuntimeService();
		Task task1 = taskService.createTaskQuery()
				.taskId(taskId)
				.taskAssignee(assignee)
				.singleResult();
		String processInstanceId = task1.getProcessInstanceId();
		String nowUserId = assignee;
		String tarActivityId = "Task_0wj3769";
		//获取待执行的任务节点
		List<Task> task = taskService.createTaskQuery().processInstanceId(processInstanceId).list();
		if(ObjectUtils.isEmpty(task)){
			// throw new Exception("sorry,the process is not started or has finished, cannot be withdrawn");
			System.out.println("sorry,the process is not started or has finished, cannot be withdrawn");
		}
//		//通过processInstanceId查询历史节点
//		List<HistoricTaskInstance> htiList = historyService.createHistoricTaskInstanceQuery()
//				.processInstanceId(processInstanceId)
//				.orderByTaskCreateTime()
//				.asc()
//				.list();
		//找到当前运行的节点
		HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
		String processDefinitionId = processInstance.getProcessDefinitionId();
		//获取流程模型
		BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
		//想要回退到的节点位置
		System.out.println(tarActivityId);
		FlowNode myFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(tarActivityId);
		//原本的活动方向
		Execution execution = runtimeService.createExecutionQuery().executionId(task.get(0).getExecutionId()).singleResult();
		String activityId = execution.getActivityId();
		FlowNode flowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(activityId);
		//记录原活动方向
		List<SequenceFlow> oriSequenceFlows = new ArrayList<SequenceFlow>();
		oriSequenceFlows.addAll(flowNode.getOutgoingFlows());
		//清理活动方向
		flowNode.getOutgoingFlows().clear();
		//建立新方向
		List<SequenceFlow> newSequenceFlowList = new ArrayList<SequenceFlow>();
		SequenceFlow newSequenceFlow = new SequenceFlow();
		newSequenceFlow.setId("newSequenceFlowId"+" ROLLBACK: "+ LocalDateTime.now());
		//新方向的源头---当前节点
		newSequenceFlow.setSourceFlowElement(flowNode);
		System.out.println("--------------new flow-----------------"+flowNode);
		//新方向的目标---要回退的节点
		System.out.println("--------------target flow-----------------"+myFlowNode);
		newSequenceFlow.setTargetFlowElement(myFlowNode);
		newSequenceFlowList.add(newSequenceFlow);
		flowNode.setOutgoingFlows(newSequenceFlowList);

		Authentication.setAuthenticatedUserId(nowUserId);
		for (int i = 0; i < task.size(); i++) {
			// TODO 多人会签节点退回 所有节点回退即可
//			taskService.deleteTask(task.get(i).getId(), "回退", Boolean.TRUE);
			taskService.addComment(task.get(i).getId(), task.get(i).getProcessInstanceId(), "回退");
			//完成任务
			System.out.println("========================完成任务====================");
			taskService.complete(task.get(i).getId());
		}

		//恢复原方向
		flowNode.setOutgoingFlows(oriSequenceFlows);
		System.out.println("------------------RollBack successfully！！----------------------------");
        return "成功";
	}

	@Override
	public Object returnAppointNode1(String taskId, String assignee) {
		//        1、创建ProcessEngine
		ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
		final TaskService taskService = processEngine.getTaskService();
		final HistoryService historyService = processEngine.getHistoryService();
		final RepositoryService repositoryService = processEngine.getRepositoryService();
		final RuntimeService runtimeService = processEngine.getRuntimeService();
		Task task1 = taskService.createTaskQuery()
				.taskId(taskId)
				.taskAssignee(assignee)
				.singleResult();
		String processInstanceId = task1.getProcessInstanceId();
		String nowUserId = assignee;
		//TODO 退回上一节点为 会签节点时 指向上一节点的网关节点
		String tarActivityId = "Gateway_1bdorji";
		//获取待执行的任务节点
		Task task = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();
		if(task == null){
			// throw new Exception("sorry,the process is not started or has finished, cannot be withdrawn");
			System.out.println("sorry,the process is not started or has finished, cannot be withdrawn");
		}
		//通过processInstanceId查询历史节点
		List<HistoricTaskInstance> htiList = historyService.createHistoricTaskInstanceQuery()
				.processInstanceId(processInstanceId)
				.orderByTaskCreateTime()
				.asc()
				.list();
		String myTaskId = null;
		HistoricTaskInstance myTask = null;
		//找到当前运行的节点
		HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
		String processDefinitionId = processInstance.getProcessDefinitionId();
		//获取流程模型
		BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
		//想要回退到的节点位置
		System.out.println(tarActivityId);
		FlowNode myFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(tarActivityId);
		//原本的活动方向
		Execution execution = runtimeService.createExecutionQuery().executionId(task.getExecutionId()).singleResult();
		String activityId = execution.getActivityId();
		FlowNode flowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(activityId);
		//记录原活动方向
		List<SequenceFlow> oriSequenceFlows = new ArrayList<SequenceFlow>();
		oriSequenceFlows.addAll(flowNode.getOutgoingFlows());
		//清理活动方向
		flowNode.getOutgoingFlows().clear();
		//建立新方向
		List<SequenceFlow> newSequenceFlowList = new ArrayList<SequenceFlow>();
		SequenceFlow newSequenceFlow = new SequenceFlow();
		newSequenceFlow.setId("newSequenceFlowId"+" ROLLBACK: "+ LocalDateTime.now());
		//新方向的源头---当前节点
		newSequenceFlow.setSourceFlowElement(flowNode);
		System.out.println("--------------new flow-----------------"+flowNode);
		//新方向的目标---要回退的节点
		System.out.println("--------------target flow-----------------"+myFlowNode);
		newSequenceFlow.setTargetFlowElement(myFlowNode);
		newSequenceFlowList.add(newSequenceFlow);
		flowNode.setOutgoingFlows(newSequenceFlowList);

		Authentication.setAuthenticatedUserId(nowUserId);
		taskService.addComment(task.getId(), task.getProcessInstanceId(), "回退");
		//完成任务
		System.out.println("========================完成任务====================");
		taskService.complete(task.getId());

		//恢复原方向
		flowNode.setOutgoingFlows(oriSequenceFlows);
		System.out.println("------------------RollBack successfully！！----------------------------");
		//将退回完成后的当前节点的task返回
//        HistoricActivityInstance historicActivityInstance = historyService.createHistoricActivityInstanceQuery().activityId(tarActivityId).singleResult();
//
//        return historicActivityInstance.getTaskId();
		return "成功";
	}

	@Resource
	ActGeBytearrayMapper actGeBytearrayMapper;

	@Override
	public Object addTask(String taskId, String assignee) {
		//        1、创建ProcessEngine
		ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
		final TaskService taskService = processEngine.getTaskService();
		final RepositoryService repositoryService = processEngine.getRepositoryService();
		Task userTask = taskService.createTaskQuery()
				.taskId(taskId)
//				.taskAssignee(assignee)
				.singleResult();

		final BpmnModel bpmnModel = repositoryService.getBpmnModel(userTask.getProcessDefinitionId());
		final Process process = bpmnModel.getMainProcess();
		process.removeFlowElement("flow4");//移除最终节点连线
		process.addFlowElement(createUserTask("add", "First task", "fred"));//新增节点
		process.addFlowElement(createSequenceFlow("usertask3", "add"));//新增节点 于原节点连线
		process.addFlowElement(createSequenceFlow("add", "endevent1"));//新增节点 于原节点连线
		//重新绘画图形
		new BpmnAutoLayout(bpmnModel).execute();
		BpmnXMLConverter converter = new BpmnXMLConverter();
//把bpmnModel对象转换成字符
		byte[] bytes = converter.convertToXML(bpmnModel);
		//清除缓存
		ProcessEngineConfigurationImpl configuration = (ProcessEngineConfigurationImpl) processEngine.getProcessEngineConfiguration();
		DeploymentManager deploymentManager = configuration.getDeploymentManager();
		deploymentManager.getProcessDefinitionCache().remove(userTask.getProcessDefinitionId());

//		String xmlContenxt = new String(bytes);
		List<ActGeBytearray> actGeBytearrayList = actGeBytearrayMapper.getActGeBytearrayList(userTask.getProcessDefinitionId());
		actGeBytearrayList = actGeBytearrayList.stream().filter(item -> item.getName().endsWith(".bpmn")).peek(item -> {
			item.setBytes(bytes);
		}).collect(Collectors.toList());
		if (ObjectUtils.isNotEmpty(actGeBytearrayList)) actGeBytearrayMapper.updateById(actGeBytearrayList.get(0));
		return null;
	}


	@Data
	private static class TaskVo {
		private String processInstanceId;
		private String id;
		private String assignee;
		private String name;
	}
	@Data
	private static class ProcessInstanceVo {
		private String processDefinitionId;
		private String id;
		private String activityId;
	}
	@Data
	private static class HistoricActivityInstanceVo {
		private String activityId;
		private String activityName;
		private String processDefinitionId;
		private String processInstanceId;
	}

	protected static UserTask createUserTask(String id, String name, String assignee) {
		UserTask userTask = new UserTask();
		userTask.setName(name);
		userTask.setId(id);
		userTask.setAssignee(assignee);
		return userTask;
	}

	protected static SequenceFlow createSequenceFlow(String from, String to) {
		SequenceFlow flow = new SequenceFlow();
		flow.setSourceRef(from);
		flow.setTargetRef(to);
		return flow;
	}
}
